<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>
    
    ES6 Symbol类型 - DSRBLOG
    
  </title>
  

  
  
  <link href="atom.xml" rel="alternate" title="DSRBLOG" type="application/atom+xml">
  <link rel="stylesheet" href="asset/css/style.min.css">
  <link rel="stylesheet" href="asset/css/doc.css">
  <script src="asset/app.js"></script>


</head>

<body> <section class="ct-body">
	<div class="container">
		<div class="columns is-variable bd-klmn-columns is-4 is-centered">
			<div class="column is-four-fifths">
				<div class="post-body single-content">
					
					<h1 class="title">
						ES6 Symbol类型
					</h1>


					<div class="media">
						
						
						<div class="media-content">
							<div class="content">
								<p>
									<span class="date">2022/08/18 02:27 上午</span>
									

									

									<br />
									<span class="tran-tags">Tags:</span>&nbsp;
									
									<a class="tag is-link is-light">#ES6新特性</a>
									

								</p>
							</div>
						</div>

					</div>
				</div>
				<article class="markdown-body single-content">
					<h2><a id="symbol%E7%9A%84%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%88%9B%E5%BB%BA" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>symbol的介绍与创建</h2>
<p>在<code>ES5</code>中，对象属性名都是字符串，容易造成属性名冲突，所以<code>ES6</code>引入了一种新的<strong>原始数据类型</strong><code>[Symbol]</code>，表示独一无二的值，它是JavaScript语言的原生数据类型之一，是一种<strong>类似于字符串</strong>的数据类型</p>
<table>
<thead>
<tr>
<th style="text-align: center">基本数据类型</th>
<th style="text-align: center">引用数据类型</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">Undefined<br/>（<strong>未定义</strong>）</td>
<td style="text-align: center">Object（对象）<br/>【<strong>包含：Function（函数）、Array（数组）、Date（日期）</strong>】</td>
</tr>
<tr>
<td style="text-align: center">String<br/>（<strong>字符串</strong>）</td>
<td style="text-align: center"></td>
</tr>
<tr>
<td style="text-align: center">Null<br/>（<strong>空值</strong>）</td>
<td style="text-align: center"></td>
</tr>
<tr>
<td style="text-align: center">Number<br/>（<strong>数字</strong>）</td>
<td style="text-align: center"></td>
</tr>
<tr>
<td style="text-align: center">Boolean<br/>（<strong>布尔</strong>）</td>
<td style="text-align: center"></td>
</tr>
<tr>
<td style="text-align: center">Symbol</td>
<td style="text-align: center"></td>
</tr>
</tbody>
</table>
<h3><a id="symbol%E7%89%B9%E7%82%B9" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>symbol特点</h3>
<ol>
<li><code>Symbol</code>的值是随机且唯一的，可以用来定义对象的私有变量、解决命名冲突的问题</li>
<li><code>Symbol</code>值不能与其他数据进行运算</li>
<li><code>Symbol</code>定义的对象属性不能使用<code>for...in</code>循环遍历，但是可以使用<code>Reflect.ownKeys</code>来获取对象的所有键名</li>
</ol>
<h3><a id="%E5%88%9B%E5%BB%BAsymbol" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>创建Symbol</h3>
<p><code>Symbol</code>值通过<code>Symbol()</code>函数生成，可以接受一个字符串作为参数，表示对<code>Symbol</code>的描述</p>
<pre class="line-numbers"><code class="language-js">//创建Symbol
let s = Symbol(); 

console.log(s, typeof s); //输出'Symbol() &quot;symbol&quot;'，唯一性在此不可见
</code></pre>
<p>函数的参数只是表示对当前 Symbol 值的描述，因此相同参数的Symbol函数的返回值是不相等的</p>
<pre class="line-numbers"><code class="language-js">let s2 = Symbol('DSR'); 
let s3 = Symbol('DSR');
   
console.log(s2); //输出'Symbol('DSR')'
   
console.log(s2 === s3); //输出fasle
</code></pre>
<h3><a id="symbol%E7%9A%84%E5%8F%96%E5%80%BC" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>Symbol的取值</h3>
<p>用<code>Symbol</code>定义的对象中的变量，取值时要用<code>[变量名]</code></p>
<pre class="line-numbers"><code class="language-js">let s1 = Symbol();
//普通写法
let obj = {};
obj[s1] = '测试';

//简写
let obj = {
    [s1]:'测试'
}

console.log(obj[s1]); //输出 '测试'
</code></pre>
<h3><a id="%E9%80%9A%E8%BF%87symbol-for%E5%88%9B%E5%BB%BA" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>通过Symbol.for()创建</h3>
<p><code>Symbol.for()</code>方法接受一个字符串作为参数，然后<strong>搜索以该参数作为名称</strong>的<code>Symbol</code>值。如果有，就返回这个 Symbol 值，否则就新建一个以该字符串为名称的 Symbol 值</p>
<pre class="line-numbers"><code class="language-js">//Symbol.for 创建
let s4 = Symbol.for('DSR'); //函数对象
let s5 = Symbol.for('DSR'); //使用这种方法创建的Symbol可以通过描述字符串得出唯一的Symbol值

console.log(s4 === s5); //输出true
</code></pre>
<h3><a id="symbol-keyfor" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>Symbol.keyFor()</h3>
<p><code>Symbol.keyFor()</code>方法能够返回一个已登记的<code>Symbol</code>类型值的<code>key</code></p>
<ul>
<li>只有通过<code>Symbol.for()</code>创建的<code>Symbol</code>会被登记到全局环境</li>
</ul>
<pre class="line-numbers"><code class="language-js">let x = () =&gt; Symbol.for('foo');
let y = Symbol.for('foo');

console.log(x === y); //输出true
</code></pre>
<h3><a id="symbol-prototype-description%E5%AE%9E%E4%BE%8B%E5%B1%9E%E6%80%A7" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>Symbol.prototype.description实例属性</h3>
<p><code>ES10(2019)</code>提供了一个<code>Symbol</code>的实例属性<code>description</code>，可以直接返回<code>Symbol</code>的描述</p>
<pre class="line-numbers"><code class="language-js">let sym = Symbol('foo');

console.log(sym.description); //输出'foo'
</code></pre>
<h2><a id="%E6%B7%BB%E5%8A%A0symbol%E5%B1%9E%E6%80%A7" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>添加Symbol属性</h2>
<p>给对象添加属性和方法，表示独一无二</p>
<h3><a id="%E6%96%B9%E6%B3%95%E4%B8%80" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>方法一</h3>
<pre class="line-numbers"><code class="language-js">let game = {
    name: &quot;俄罗斯方块&quot;;
    up: function(){};
    down: function(){};
};

//声明一个对象
let methods = {
    up: Symbol();
    dowm: Symbol();
};

//向对象添加属性
game[methods.up] = function(){
    console.log(&quot;上升&quot;)
};
game[methods.down] = funnction(){
    console.log(&quot;下降&quot;)
};
</code></pre>
<h3><a id="%E6%96%B9%E6%B3%95%E4%BA%8C" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>方法二</h3>
<pre class="line-numbers"><code class="language-js">let game = {
    name: &quot;狼人杀&quot;;
    [Symbol('say')]: function(){
        console.log(&quot;发言&quot;);
    };
    [Symbol('dark')]: function(){
        console.log(&quot;天黑请闭眼&quot;);
    }
};
</code></pre>
<h2><a id="%E8%8E%B7%E5%8F%96symbol%E5%A3%B0%E6%98%8E%E7%9A%84%E5%B1%9E%E6%80%A7%E5%90%8D" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>获取Symbol声明的属性名</h2>
<p>遍历对象时，<code>Symbol</code>作为属性名，不会出现在<code>for...in</code>、<code>for...of</code>循环中，也不会被<code>Object.keys()</code>、<code>Object.getOwnPropertyName()</code>、<code>JSON.stringify()</code>返回</p>
<pre class="line-numbers"><code class="language-js">const obj = {};
let a = Symbol('a');
let b = Symbol('b');

obj[a] = 'Hello';
obj[b] = 'World';
</code></pre>
<h3><a id="object-getownpropertysymbols" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>Object.getOwnpropertySymbols()</h3>
<p>该方法可以获取制定对象的<strong>所有</strong> <code>Symbol</code>属性名，并返回一个数组，数值成员是当前对象的<strong>所有用作属性名</strong>的<code>Symbol</code>值</p>
<pre class="line-numbers"><code class="language-js">const objectSymbols = Object.getOwnPropertySymbols(obj);

objectSymbols; //返回[Symbol(a), Symbol(b)]
</code></pre>
<h3><a id="reflect-ownkeys%E6%96%B9%E6%B3%95" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>Reflect.ownKeys()方法</h3>
<pre class="line-numbers"><code class="language-js">const objectSymbols = Reflect.ownKeys(obj);

objectSymbols; //返回[Symbol(a), Symbol(b)]
</code></pre>
<h2><a id="symbol%E5%BA%94%E7%94%A8%E5%AE%9E%E4%BE%8B" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>Symbol应用实例</h2>
<h3><a id="%E6%B6%88%E9%99%A4%E9%AD%94%E6%9C%AF%E5%AD%97%E7%AC%A6%E4%B8%B2" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>消除魔术字符串</h3>
<p>风格良好的代码应该尽量消除魔术字符串，改由含义清晰的变量代替<br />
<strong>魔术字符串：</strong> 在代码中多次出现、与代码形成强耦合的某个具体字符串或数值</p>
<h4><a id="%E6%94%B9%E8%BF%9B%E5%89%8D" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>改进前</h4>
<pre class="line-numbers"><code class="language-js">function getArea(shape, options) {
  let area = 0;

  switch (shape) {
    case 'Triangle': // 魔术字符串
      area = .5 * options.width * options.height;
      break;
  }

  return area;
}

getArea('Triangle', { width: 100, height: 100 }); // 魔术字符串
</code></pre>
<p><strong>Triangle</strong>是其中的魔术字符串</p>
<h4><a id="%E6%94%B9%E8%BF%9B%E5%90%8E" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>改进后</h4>
<pre class="line-numbers"><code class="language-js">const shapeType = {
  triangle: 'Triangle' // 用于替代魔术字符串
};

function getArea(shape, options) {
  let area = 0;
  switch (shape) {
    case shapeType.triangle:// 替代原有魔术字符串
      area = .5 * options.width * options.height;
      break;
  }
  return area;
}

getArea(shapeType.triangle, { width: 100, height: 100 }); // 替代原有魔术字符串
</code></pre>
<p>使用<strong>shapeType.triangle</strong>替代原有的魔术字符串</p>
<h4><a id="%E4%BD%BF%E7%94%A8symbol%E5%AD%97%E7%AC%A6%E4%B8%B2" class="anchor" aria-hidden="true"><span class="octicon octicon-link"></span></a>使用Symbol字符串</h4>
<p>在以上代码中，<code>shapeType.triangle</code>的具体值并不重要，只要确保不会跟其他属性产生冲突即可，可以改用<code>Symbol</code>值替代</p>
<pre class="line-numbers"><code class="language-js">const shapeType = {
  triangle: Symbol() // 用于替代魔术字符串
};
</code></pre>

				</article>
				<div class="comments-wrap">
					<div class="share-comments">
						

						

						
					</div>
				</div><!-- end comments wrap -->
			</div>
		</div><!-- end columns -->
	</div><!-- end container -->
</section>  














<script src="asset/prism.js"></script>









</body>

</html>